package com.ruiao.car.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruiao.car.config.BusinessException;
import com.ruiao.car.constant.Constant;
import com.ruiao.car.dto.AccountDto;
import com.ruiao.car.dto.ResultDto;
import com.ruiao.car.dto.UserDto;
import com.ruiao.car.dto.UserUpdateDto;
import com.ruiao.car.entity.Account;
import com.ruiao.car.entity.AccountAttach;
import com.ruiao.car.entity.Sms;
import com.ruiao.car.enums.AppIdEnum;
import com.ruiao.car.enums.ResultEnum;
import com.ruiao.car.mapper.AccountMapper;
import com.ruiao.car.service.IAccountAttachService;
import com.ruiao.car.service.IAccountService;
import com.ruiao.car.service.ISmsService;
import com.ruiao.car.service.RedisService;
import com.ruiao.car.utils.AccountHeaderUtil;
import com.ruiao.car.utils.AccountThreadLocal;
import com.ruiao.car.utils.DateUtils;
import com.ruiao.car.utils.HeaderUtil;
import com.ruiao.car.utils.MD5Utils;
import com.ruiao.car.utils.TokenProcessor;
import com.ruiao.car.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author jsonval@163.com
 * @since 2020-06-12
 */
@Slf4j
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountService {
	
	@Autowired
	private RedisService redisService;
	
	@Autowired
	private ISmsService smsService;

	@Autowired
	private IAccountAttachService accountAttachService;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public Account selectAccountByPhone(String phone) {
		log.info("====phone===" + phone);
		QueryWrapper queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("mobile_phone", phone);
		return this.getOne(queryWrapper);
	}

	@Override
	public AccountDto selectAccountByToken(Long userId) {
		Account account = getById(userId);
		if(account != null) {
			AccountDto dto = new AccountDto();
			BeanUtils.copyProperties(account, dto);
			return dto;
		}
		return null;
	}

	@Override
	public ResultDto login(String phone, String password) throws BusinessException {
		
		if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(password)) {
			throw new BusinessException(ResultEnum.LOSE_PARAM);
		}
		Account user = checkUser(phone);
		// 账号密码错误
		if (!user.getPassword().equals(MD5Utils.getMD5String(password))) {
			throw new BusinessException(ResultEnum.username_pwd_error);
		}
		AccountDto accountDto = checkAccount(user);
		return new ResultDto(ResultEnum.SUCCESS, accountDto);
	}
	
	private Account checkUser(String phone) throws BusinessException {
		Account user = this.selectAccountByPhone(phone);
		if (user == null) {
			throw new BusinessException(ResultEnum.username_pwd_error);
		}
		return user;
	}
	
	private AccountDto checkAccount(Account user) throws BusinessException {
		//用户状态 show正常 del 删除 black拉黑 frozen冻结
		if (!"show".equals(user.getAccountStatus())) {
			throw new BusinessException(ResultEnum.CODE_ACCOUNT_LOCK);
		}
		AccountDto accountDto = new AccountDto();
		BeanUtils.copyProperties(user, accountDto);
		accountDto.setToken(TokenProcessor.getInstance().generateToken(user.getId().toString(), true));
		redisService.set(Constant.TOKEN + accountDto.getToken(), user.getId(), 24 * 60 * 60);
		return accountDto;
	}

	@Override
	public ResultDto quickSmsLogin(String phone, String verificationCode) throws BusinessException {
		if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(verificationCode)) {
			throw new BusinessException(ResultEnum.LOSE_PARAM);
		}
		Account user = checkUser(phone);
		checkSms(phone,verificationCode,(byte)1,(byte)2);
		AccountDto accountDto = checkAccount(user);
		return new ResultDto(ResultEnum.SUCCESS, accountDto);
	}
	
	
	private void checkSms(String phone,String verificationCode,byte status,byte type) throws BusinessException {
		Sms param = new Sms();
		param.setMobile(phone);
		param.setStatus(status);
		param.setType(type);
		param = smsService.selectSmsByPhone(param);
		
		// 短信校验
		if (param == null) {
			throw new BusinessException(ResultEnum.CODE_SMS_NOEXIST);
		}
		
		// 是否在有效期内
		if (param.getCreateDate().before(DateUtils.getBeforeDate(new Date(), -5))) {
			param.setStatus((byte)0);
			smsService.updateSms(param);
			throw new BusinessException(ResultEnum.CODE_AUTHCODE_INVALID);
		}
		
		// 是否正确
		if (!verificationCode.equals(param.getCode())) {
			throw new BusinessException(ResultEnum.CODE_AUTHCODE_FAILED);
		}
		
		System.out.println(param);
		param.setStatus((byte)0);
		smsService.updateSms(param);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResultDto reg(String phone, String password, String verificationCode) throws BusinessException {
		if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(verificationCode)
				&& StringUtils.isEmpty(password) ) {
			throw new BusinessException(ResultEnum.LOSE_PARAM);
		}
		Account user = this.selectAccountByPhone(phone);
		if (user != null) {
			throw new BusinessException(ResultEnum.Mobile_error);
		}
		
//		checkSms(phone,verificationCode,(byte)1,(byte)1);
		HeaderUtil headerUtil = AccountThreadLocal.get().getHeaderUtil();
		user = new Account();
		user.setCreateTime(new Date());
		user.setPassword(MD5Utils.getMD5String(password));
		user.setMobilePhone(phone);
		user.setAppId(headerUtil.getAppId());
		user.setAccountStatus("show");
		user.setDeviceId(headerUtil.getDeviceId());
		user.setOsType(headerUtil.getOsType());
		user.setIpAddress(headerUtil.getIp());
		user.setAppChannel(headerUtil.getAppChannel());
		user.setRegTime(new Date());
		user.setAvatar(AppIdEnum.getAppIdEnum(user.getAppId()).getAvatar());
		this.baseMapper.insert(user);

		AccountAttach accountAttach = AccountAttach.builder().accountId(user.getId())
				.mltAddress(Constant.MLT_PRE+SnowflakeIdWorker.getInstance().nextId())
				.appId(user.getAppId()).integralTotal(new BigDecimal(0)).build();
		accountAttachService.save(accountAttach);

		return new ResultDto(ResultEnum.SUCCESS, user);
	}

	@Override
	public ResultDto updateUser(UserUpdateDto dto) {
		AccountHeaderUtil accountThreadLocal =  AccountThreadLocal.get();
		Account account = this.getById(accountThreadLocal.getAccount().getId());
		if(StringUtils.isNotEmpty(dto.getNickName())){
			account.setNickName(dto.getNickName());
		}
		if(StringUtils.isNotEmpty(dto.getAvatar())){
			account.setAvatar(dto.getAvatar());
		}
		if(StringUtils.isNotEmpty(dto.getIntroduction())){
			account.setIntroduction(dto.getIntroduction());
		}
		return new ResultDto(ResultEnum.SUCCESS,this.updateById(account));
	}

	@Override
	public ResultDto<AccountDto> getUserInfo() {
		AccountHeaderUtil accountThreadLocal =  AccountThreadLocal.get();
		Account user = this.getById(accountThreadLocal.getAccount().getId());
		AccountDto accountDto = new AccountDto();
		BeanUtils.copyProperties(user, accountDto);

		AccountAttach accountAttach = accountAttachService.getOne(
				new QueryWrapper<AccountAttach>().lambda().eq(AccountAttach::getAccountId,user.getId()));

		if(null!=accountAttach){
			accountDto.setIntegralTotal(accountAttach.getIntegralTotal());
		}

		return new ResultDto(ResultEnum.SUCCESS, accountDto);
	}


}
